#pragma once

#include <Ice/Ice.h>
#include <IceUtil/IceUtil.h>
#include <Glacier2/Session.h>
#include <Glacier2/Router.h>

class IceDispatcher : public Ice::Dispatcher
{
public:
	IceDispatcher(const Ice::LoggerPtr& logger);

	void dispatch(const Ice::DispatcherCallPtr& call, const Ice::ConnectionPtr&);

	void update();

private:
	IceUtil::Mutex _dispatchCallMutex;
	std::vector<Ice::DispatcherCallPtr*> _dispatcherCallList;

	Ice::LoggerPtr _logger;

};

class SessionHelper;

class SessionStats : public Ice::Stats
{
public:
	SessionStats();

	virtual void bytesSent(const ::std::string&, ::Ice::Int);
	virtual void bytesReceived(const ::std::string&, ::Ice::Int);

	IceUtil::Time _lastSendTime;
	IceUtil::Time _lastReceiveTime;
};

class SessionCallback
{ 
public:
	virtual ~SessionCallback(){}
    virtual void createdCommunicator(SessionHelper* session) = 0;   
    virtual void connected(SessionHelper* session) = 0;
    virtual void disconnected(SessionHelper* session) = 0;  
    virtual void connectFailed(SessionHelper* session,const Ice::Exception& ex) = 0;
};

class SessionPingThreadI;
typedef IceUtil::Handle<SessionPingThreadI> SessionPingThreadIPtr;


class IceDispatcher;
class ConnectStrategy;
class SessionHelper : public IceUtil::Shared
{
public:
	friend class ConnectionThread;
	friend class DestroyInternalThread;
	friend class IceDispatcher;
public:
	SessionHelper(SessionCallback* callback, Ice::InitializationData* initData);
	virtual ~SessionHelper(void);
	
	void destroy();
	void connect(const std::string username,const std::string password);
	bool	isConnected();

	Glacier2::SessionPrx  session();
	Ice::CommunicatorPtr  communicator();

	std::string categoryForClient();
	Ice::ObjectPrx	addWithUUID(Ice::ObjectPtr servant);
	Ice::ObjectAdapterPtr objectAdapter();
	Ice::Identity createCallbackIdentity(const std::string& name);

	void update();
private:
	void    connected(Glacier2::RouterPrx router, Glacier2::SessionPrx session);
	void    dispatchCallback(Ice::DispatcherCall* call,Ice::ConnectionPtr conn );
	void    dispatchCallbackAndWait(Ice::DispatcherCall* call);
    void	connectImpl(const ConnectStrategy& factory);
	void	destroyInternal();
    
	void    refreshException(const Ice::Exception& ex);
private:
	IceInternal::Handle<SessionStats> _stats;
	Ice::InitializationData* _initData;
	Ice::CommunicatorPtr _communicator;
	Glacier2::RouterPrx _router;
	Ice::ObjectAdapterPtr _adapter;
	Glacier2::SessionPrx _session;
	std::string _category;

	SessionCallback*      _callback;

	bool  _destroy;
	bool  _connected;

	IceUtil::Mutex _sessionMutex;
	Ice::Long _refreshPeriod;
};
